#ifndef _ACTOR_H_
#define _ACTOR_H_

#include "vec.hpp"
#include "grid.hpp"

class Image;
class Sound;

class Stage;

#include <cfloat>

#include "cue.hpp"

class Player;
class Item;
class Weapon;

class Actor
{
public:
	Actor();
	virtual ~Actor();

	void Reset();

	virtual void Init(float x, float y, Cue & cue)
	{
	}

	virtual void Update()
	{
	}
	
	Vec2f OutVel(float upfrac = 1);
	Vec2f OutPos(float upfrac = 0);
	Vec2f LookPos(float upfrac = 0);
	void LookAt(float upfrac);
	void Out(float upfrac);

	bool Gone();

	bool Exists()
	{
		return hp > -1;
	}

	bool Live()
	{
		return hp > 0;
	}

	float Face(float d = 0)
	{
		if (d)
		       dir = d < 0 ? -1 : 1;
		return dir;
	}

	bool BHitting(Box2f & b)
	{
		return body.Hitting(b);
	}

	bool Hitting(Actor *a)
	{
		return a != 0 && BHitting(a->body);
	}

	bool StgHitting(int axis)
	{
		return stghit[axis] < FLT_MAX;
	}

	void Kill()
	{
		hp = 0;
	}

	void Bury()
	{
		hp = -1;
	}

protected:
	int hp;

	Box2f body;
	Vec2f vel;
	float dir;
	Grid grid;

	Vec2f stghit;

	float red, grn, blu, alpha;
	Image *img;
	float frame;
	Sound *snd;
	int chan;
};

#include <list>

class ActList
{
public:
	ActList();
	~ActList();

	void Add(Actor *a);

	void Update();
	void Out(float upfrac);

	void Bury();
	void Clear();

	typedef std::list<Actor*>::iterator Iter;

private:
	std::list<Actor*> actors;
};

extern ActList AllActs;

template <class Act, unsigned int N>
class ActPool
{
public:
	ActPool()
	{
	}
	
	~ActPool()
	{
	}

	unsigned Count()
	{
		return N;
	}

	Act & Put(unsigned int i, float x, float y, Cue & cue)
	{
		Act & a = actors[i];
		a.Reset();
		a.Init(x, y, cue);
		AllActs.Add(&a);
		return a;
	}

	Act & Get(unsigned int i)
	{
		return actors[i];
	}

	Act* New()
	{
		Act *a = 0;
		for (unsigned int i = 0; i < N && a == 0; ++i)
		{
			if (!actors[i].Exists())
			{
				a = &actors[i];
				a->Reset();
			}
		}
		return a;
	}

	void DelI(int i)
	{
		actors[i].Bury();
	}

	void Del(Act *a)
	{
		int i = (a - actors)/sizeof(Act);
		if (0 <= i && i < N)
			DelI(i);
	}

	Act* Init(float x, float y, Cue & cue)
	{
		Act *a = New();
		if (a)
		{
			a->Init(x, y, cue);
			AllActs.Add(a);
		}
		return a;
	}

	void Update()
	{
		for (unsigned i = 0; i < N; ++i)
		{
			if (actors[i].Live())
				actors[i].Update();
		}
	}

	template <class Act2>
	void Hit(Act2 & a2)
	{
		for (unsigned int i = 0; i < N; ++i)
		{
			if (actors[i].Live() && a2.Hitting(&actors[i]))
			{
				actors[i].Hit(a2);
				a2.Hit(actors[i]);
			}
		}
	}

	template <class Act2, unsigned int N2>
	void Hit(ActPool<Act2, N2> & actors2)
	{
		for (unsigned int i2 = 0; i2 < N2; ++i2)
		{
			Act2 & a2 = actors2.Get(i2);
			if (a2.Live())
				Hit(a2);
		}
	}

	void Clear()
	{
		for (unsigned i = 0; i < N; ++i)
		{
			actors[i].Bury();
		}
	}

private:
	Act actors[N];
};

#endif
